package jdk8;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.StampedLock;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Concurrent {
	public static void main(String[] args) throws InterruptedException {

		BankAccountWithStampedLock account = new BankAccountWithStampedLock();

		ExecutorService pool = Executors.newCachedThreadPool();

		IntFunction<? extends Callable<Double>> mapper = x -> () -> {
			account.deposit(x);
			return 0d;
		};

		List<Callable<Double>> callables = IntStream.range(1, 5).mapToObj(mapper).collect(Collectors.toList());

		pool.invokeAll(callables).forEach(x -> {
			try {
				System.out.println(x.get());
			} catch (InterruptedException | ExecutionException e) {
				e.printStackTrace();
			}
		});

		System.out.println(account.getBalance());

		pool.shutdown();
	}
}

class BankAccountWithStampedLock {

	private final StampedLock lock = new StampedLock();
	private double balance;

	public void deposit(double amount) {
		long stamp = lock.writeLock();
		try {
			balance = balance + amount;
		} finally {
			lock.unlockWrite(stamp);
		}
	}

	public double getBalance() {
		long stamp = lock.readLock();
		try {
			return balance;
		} finally {
			lock.unlockRead(stamp);
		}
	}
}
